<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

</body>
<script>
    // ========================================================================================
    // Class类

    // // 声明一个class
    // class Person {
    //     // 静态属性：
    //     // 类本身就含有而不是实例特有的，直接可以通过类名来调用
    //     static type = 'people'
    //     // 构造函数
    //     constructor(a, b) {
    //         this.a = a;
    //         this.b = b;
    //     }
    //     // 类似于es5原型方法：
    //     say() { }
    //     // 静态方法
    //     static eat() {
    //         console.log('葫芦头泡馍');
    //     }
    // }


    // // 等价于：
    // function Person2(a, b) {
    //     this.a = a;
    //     this.b = b;
    // }
    // // 静态属性，构造函数直接调用
    // Person2.type = 'people'
    // // 原型方法
    // Person2.prototype.say = function () { }
    // // 静态方法
    // Person2.eat = function () {
    //     console.log('油泼面');

    // }


    // var p1 = new Person(1, 2);
    // var p2 = new Person2(3, 4);
    // console.log(p1, p2);
    // console.dir(Person);
    // console.dir(Person2);
    // console.log(Person.type);
    // console.log(Person2.type);
    // Person.eat();
    // Person2.eat();




    // -----------------------------------------------------------------------------------
    // 继承
    // class Point {
    //     // 私有属性
    //     // 只能在类的内部使用，如果要在类的外面使用，可以声明一个方法把私有属性返回出去
    //     #a = 1;
    //     // 静态属性
    //     static type = 'people'
    //     constructor(where) {
    //         this.where = where;
    //     }
    //     eat() {
    //         console.log('我想吃泡馍');
    //         return '我想吃泡馍'
    //     }
    //     // 私有方法
    //     #getSelf() {
    //         console.log('我是私有的');
    //     }
    //     // 获取私有属性（声明一个方法把私有属性和方法返回出去）
    //     getA() {
    //         // 获取私有方法
    //         this.#getSelf()
    //         // 这里的this指向的是类的实例
    //         return console.log(this.#a);
    //     }
    // }
    // var p = new Point('西安')
    // // p.eat();
    // // 获取私有属性和方法
    // // p.getA()


    // // extends继承
    // // ChildPoint子类继承Point父类的所有属性和方法
    // class ChildPoint extends Point {
    //     constructor(where, shopName) {
    //         super(where)
    //         this.shopName = shopName
    //     }
    //     drink() {
    //         console.log('我想喝胡辣汤');
    //         return '我想喝胡辣汤'
    //     }
    //     toString() {
    //         return (`我是${this.where}的,我想去${this.shopName},${super.eat()}还有${this.drink()}`)
    //     }
    // }
    // // console.log(ChildPoint.type);
    // var p2 = new ChildPoint('西安', '葫芦头')
    // // p2.eat();
    // // p2.drink();
    // console.log(p2.toString());








    // ========================================================================================
    // Promise
    // Promise是es6推出的一个完美的异步解决方案
    // Promise是一个构造函数，该函数有一个回调函数作为参数
    // 这个回调函数有两个参数resolve和reject，分别是修改成功状态方法和修改失败状态方法
    // Promise返回一个实例对象

    // Promise三种状态：
    // 1.pending（准备中）初始状态
    // 2.fulfilled/resolved（已成功）
    // 3.rejected（已失败）
    // 状态的改变只有两种可能pending > fulfilled/resolved和pending > rejected
    // new Promise((resolve, reject) => {
    //     if (Math.random() > 0.5) {
    //         resolve('成功')
    //     } else {
    //         reject('失败')
    //     }
    // })
    //     // 链式调用
    //     // res接受resolve的参数
    //     // err接收reject的参数
    //     // then方法的第二个回调函数用来接收reject传来的参数，这种写法不多见一般用.catch方法
    //     .then((res) => {
    //         console.log('第一个回调', res);
    //         return res
    //     }, err => {
    //         console.log('第一个回调', err);
    //         return err
    //     })
    //     .then((res) => {
    //         console.log('第二个回调', res);
    //         return res
    //     })
    //     // catch用来接收失败的参数
    //     .catch((err) => {
    //         console.log('第二个回调', err);
    //         return err
    //     })
    //     // finally,无论成功还是失败最后都会执行
    // .finally(() => {
    //     console.log('finally');
    // })


    // 等价的
    //可以实例调用
    // ！！！失败的话有点问题会报错！！！
    // var p = new Promise((resolve, reject) => {
    //     if (Math.random() > 0.5) {
    //         resolve('成功')
    //     } else {
    //         reject('失败')
    //     }
    // })
    // p.then((res) => {
    //     console.log('第一个回调', res);
    //     return res
    // }/*, err => {
    //     console.log('第一个回调', err);
    //     return err
    // }*/)//报一个错
    // p.catch((err) => {
    //     console.log('第一个回调', err);
    //     return err
    // })//报两个错
    // p.finally(() => {
    //     console.log('finally');
    // })


    // -----------------------------------------------------------------------------------
    // 模拟异步ajax操作
    // new Promise((resolve, reject) => {
    //     console.log('同步');
    //     // 模拟异步ajax操作
    //     setTimeout(() => {
    //         if (Math.random() > 0.5) {
    //             resolve('成功')
    //         } else {
    //             reject('失败')
    //         }
    //     }, 2000)
    // })
    //     .then((res) => {
    //         console.log('第一个回调', res);
    //         return res
    //     })
    //     .catch((err) => {
    //         console.log('第一个回调', err);
    //         return err
    //     })
    //     .finally(() => {
    //         console.log('finally');
    //     })



    // -----------------------------------------------------------------------------------
    // Promise静态方法：
    // all()并发处理多个异步任务，所有任务都执行成功才能得到结果
    // race()并发处理多个异步任务，只要有一个任务完成就可以得到结果（谁跑得快，就以谁为执行回调）
    // any()并发处理多个异步任务，只要有一个任务成功就得到结果（谁先跑完，以谁为执行回调）
    // resolve()将对象的状态转为成功状态
    // reject()将对象的状态转为失败状态


    // function fn(num) {
    //     var p = new Promise((resolve, reject) => {
    //         setTimeout(() => {
    //             if (num > 5) {
    //                 resolve('p1成功' + num)
    //             } else {
    //                 reject('p1失败' + num)
    //             }
    //         }, 2000)
    //     })
    //     return p
    // }
    // function fn2(num) {
    //     var p = new Promise((resolve, reject) => {
    //         setTimeout(() => {
    //             if (num > 5) {
    //                 resolve('p2成功' + num)
    //             } else {
    //                 reject('p2失败' + num)
    //             }
    //         }, 2000)
    //     })
    //     return p
    // }


    // // all
    // Promise.all([fn(4), fn2(5)]).then((res) => {
    //     console.log(res);
    // }).catch((err)=>{
    //     console.log(err);
    // })
    // // race
    // Promise.race([fn(6), fn2(4)]).then((res) => {
    //     console.log(res);
    // }).catch((err) => {
    //     console.log(err);
    // })
    // // any
    // Promise.any([fn(4), fn2(6)]).then((res) => {
    //     console.log(res);
    // }).catch((err) => {
    //     console.log(err);
    // })





    // -----------------------------------------------------------------------------------
    // new Promise((resolve, reject) => {
    //     setTimeout(() => {
    //         if (Math.random() > 0.5) {
    //             resolve('成功')
    //         } else {
    //             reject('失败')
    //         }
    //     }, 1000)
    // })
    //     .then((res) => {
    //         console.log('then1第一个回调', res);
    //         return res
    //     }, err => {
    //         console.log('then2第一个回调', err);
    //         return err
    //     })
    //     .catch((err) => {
    //         console.log('catch第一个回调', err);
    //         return err
    //     })
    //     .finally(() => {
    //         console.log('finally');
    //     })

    // // 手写Promise
    // var MyPromise = (function (window) {
    //     // 三个状态会多次使用到所以不建议写死
    //     const PENDING = 'pending'
    //     const RESOLVED = 'resolved'
    //     const REJECTED = 'rejected'
    //     // 返回一个class，所以可以实例化
    //     return class MyPromise {
    //         // 构造函数，参数是一个回调函数
    //         constructor(fn) {
    //             // 默认状态
    //             this.status = PENDING
    //             // 成功状态的数据
    //             this.value = undefined
    //             // 失败状态的数据
    //             this.reason = undefined
    //             // 因为要支持异步操作，所以需要把回调用队列保存起来，时机到了就执行
    //             // 成功的
    //             this.onFulfilledCallbacks = []
    //             //失败的
    //             this.inRejectedCallbacks = []
    //             // 声明成功的方法
    //             const resolve = value => {
    //                 // 只有状态是等待时修改
    //                 if (this.status === PENDING) {
    //                     // 修改为成功状态
    //                     this.status = RESOLVED
    //                     // 保存成功数据
    //                     this.value = value
    //                     // 状态变为成功就执行成功队列里的函数
    //                     this.onFulfilledCallbacks.forEach(cb => cb())
    //                 }
    //             }
    //             // 声明失败的方法
    //             const reject = value => {
    //                 // 只有状态是等待时修改
    //                 if (this.status === PENDING) {
    //                     // 修改为失败状态
    //                     this.status = REJECTED
    //                     // 保存失败数据
    //                     this.reason = value
    //                     // 状态变为失败就执行失败队列里的函数
    //                     this.inRejectedCallbacks.forEach(cb => cb())
    //                     // this.inRejectedCallbacks.map(cb => cb())
    //                 }
    //             }
    //             // 同步代码的错误处理要使用try catch
    //             try {
    //                 // 调用构造函数的参数
    //                 // 传入创建好的两个方法
    //                 fn(resolve, reject)
    //             } catch (error) {
    //                 // 出现错误把改为失败状态
    //                 reject(error)
    //             }
    //         }
    //         // 成功回调，失败回调
    //         then(onFulfilled, inRejected) {
    //             // 状态为成功执行第一个回调，状态为失败执行第二个回调
    //             if (this.status === RESOLVED) {
    //                 // 调用第一个成功的回调
    //                 onFulfilled && onFulfilled(this.value)
    //             }
    //             if (this.status === REJECTED) {
    //                 // 调用第二个失败的回调
    //                 inRejected && inRejected(this.reason)
    //             }
    //             // 因为构造函数里的异步代码，起初是不会执行的，所以状态为等待
    //             if (this.status === PENDING) {
    //                 // 把成功的回调添加到队列中
    //                 // 由于要接收参数所以使用回调函数就可以接收参数
    //                 this.onFulfilledCallbacks.push(() => {
    //                     onFulfilled && onFulfilled(this.value)
    //                 })
    //                 // 把失败的回调添加到队列中
    //                 this.inRejectedCallbacks.push(() => {
    //                     inRejected && inRejected(this.reason)
    //                 })
    //             }
    //         }
    //     }

    // })(window)


    // // 测试
    // new MyPromise((resolve, reject) => {
    //     setTimeout(() => {
    //         if (Math.random() > 0.5) {
    //             resolve('成功')
    //         } else {
    //             reject('失败')
    //         }
    //     }, 3000)
    // })
    //     .then((res) => {
    //         console.log('then1第一个回调', res);

    //     }, err => {
    //         console.log('then2第一个回调', err);

    //     })




    // ========================================================================================
    // async，await
    // 在Promise基础上的一个优化
    // Promise是一个异步解决方案，解决了回调的问题，回调地狱的本质是要控制异步的顺序
    // 背景：Promise本质上其实就是把传统的嵌套回调的写法优化成了链式调用，这个本质上还是回调函数
    // 把异步的回调形式进化成了同步写法,无法写在顶层，必须在函数声明使用
    new Promise((resolve, reject) => {
        resolve('成功')
    }).then((res) => {
        console.log('第一个回调', res);

    })
    // 特点：
    // 1.异步代码同步化
    // 2.async和await必须写在一起，不能分开
    // 3.async和await是错误的处理，要使用try catch来捕获
    // 4.async是Generator（生成器）的语法糖。（是基于Promise实现的）
    async function fn() {
        const res = await Promise.resolve('成功');
        console.log('第一个回调', res)
    }
    fn()

    // 5.返回值是Promise，如果await后面不是Promise，那么会包装成Promise 
    async function fn() {
        const res = await 1;
        console.log(res)
        return res
    }
    fn().then((res) => {
        console.log(res);
    })
    // await函数必须写在async函数内部，无法写在顶层，但是最新的语法es6已经支持了顶层await原理，可以理解为js引擎就是全局作用域外面包了一层async
    // 小结：async，await是Promise的优化，不能取代Promise，只能增强，所以项目中优先使用async，await，其次Promise












</script>

</html>